﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using System.Xml.Linq;

namespace Notorious_World_Editor
{
    public partial class Form1 : Form
    {
        int tileSetID = -1;
        int backImageID = -1;

        string tileSetImagePath = string.Empty;
        string backImagePath    = string.Empty;
        string tileSetFileName  = string.Empty;
        string backFileName     = string.Empty;

        public Tile_Selector tool = null;

        SGP.ManagedDirect3D d3D = SGP.ManagedDirect3D.Instance;
        SGP.ManagedTextureManager tm = SGP.ManagedTextureManager.Instance;

        public Size tileSetSize = new Size(16, 44);
        public Size tileSize = new Size(32, 32);
        Size levelSize = new Size(30, 30);

        Point[, ,] map = new Point[6, 30, 30];
        String[, ,] events = new String[6, 30, 30];

        int drawLayer = 3;
        int[] layerScrollRates = new int[6];

        bool[] showLayer = new bool[6];

        bool showGrid = true;

        Rectangle[] rooms;
        int numberOfRooms = 0;
        Point roomStart;
        Point roomEnd;
        Rectangle drawnRoom;

        Point dragClick = new Point(0, 0);

        Color gridColor = Color.Yellow;
        Color selectedColor = Color.DeepPink;
        Color bgColor = Color.Teal;

        struct Block
        {
            public Point[,] tiles;
            public Rectangle selectedTiles;
        }

        Block selectedBlock;

        bool looping = true;

        public bool Looping
        {
            get { return looping; }
            set { looping = value; }
        }

        public Form1()
        {
            InitializeComponent();
            looping = true;
            d3D.InitManagedDirect3D(splitContainer1.Panel1);
            tm.InitManagedTextureManager(d3D.Device, d3D.Sprite);

            buttonGridColor.BackColor = gridColor;
            buttonSelectionColor.BackColor = selectedColor;
            buttonBGColor.BackColor = bgColor;

            numericUpDownLevelWidth.Value = 30;
            numericUpDownLevelHeight.Value = 30;

            numericUpDownTileWidth.Value = 32;
            numericUpDownTileHeight.Value = 32;

            numericUpDownScrollRate0.Value = 100;
            numericUpDownScrollRate1.Value = 100;
            numericUpDownScrollRate2.Value = 100;
            numericUpDownScrollRate3.Value = 100;
            numericUpDownScrollRate4.Value = 100;
            numericUpDownScrollRate5.Value = 100;

            for (int x = 0; x < 6; x++)
            {
                checkedListBoxShowLayers.SetItemChecked(x, true);
                showLayer[x] = true;
                layerScrollRates[x] = 100;
            }

            listBox1.SelectedIndex = 0;

            OpenFileDialog ofile = new OpenFileDialog();
            ofile.Title = "Load Tileset Image...";
            ofile.Filter = "All Files|*.*|Image Files|*.png; *.jp*g; *.bmp";
            ofile.FilterIndex = 2;
            string path = Environment.CurrentDirectory;

            if (path.Contains("\\bin\\Debug"))
            {
                path = "..\\..\\Resources\\";
            }

            ofile.InitialDirectory = path;
            ofile.RestoreDirectory = true;

            if (ofile.CheckPathExists == false)
            {
                ofile.InitialDirectory = Environment.CurrentDirectory;
            }
            else
            {
                DialogResult dlgRes = ofile.ShowDialog(this);
                if (dlgRes == DialogResult.OK)
                {
                    tileSetImagePath = ofile.FileName;
                    tileSetFileName = ofile.SafeFileName;

                    tileSetID = tm.LoadTexture(ofile.FileName, 0);
                }
                else if (dlgRes == DialogResult.Cancel)
                {
                    looping = false;
                    d3D.Shutdown();
                    tm.ShutdownManagedTextureManager();
                    Application.Exit();
                }
            }

            // Init entire map to transparent tile 7 and event 0
            if (looping)
            {
                for (int l = 5; l >= 0; l--)
                {
                    for (int x = 0; x < levelSize.Width; x++)
                    {
                        for (int y = 0; y < levelSize.Height; y++)
                        {
                            map[l, x, y] = new Point(7, 0);
                            events[l, x, y] = "0";
                        }
                    }
                }
            }

            if (looping)
                buttonTileSelector_Click(this, EventArgs.Empty);
        }

        public void Update()
        {
            for (int x = 0; x < 6; x++)
            {
                if (checkedListBoxShowLayers.GetItemCheckState(x) == CheckState.Checked)
                    showLayer[x] = true;
                else if (checkedListBoxShowLayers.GetItemCheckState(x) == CheckState.Unchecked)
                {
                    showLayer[x] = false;
                    checkBoxLayersShowAll.Checked = false;
                }
            }

            DisplayScrollBars();
            SetScrollBarValues();

            if (tool != null)
            {
                tool.Update();
            }
        }

        private void DisplayScrollBars()
        {
            if (splitContainer1.Panel1.Width > levelSize.Width * tileSize.Width + vScrollBar1.Width)
            {
                hScrollBar1.Visible = false;
            }
            else
            {
                hScrollBar1.Visible = true;
            }

            if (splitContainer1.Panel1.Height > levelSize.Height * tileSize.Height + hScrollBar1.Height)
            {
                vScrollBar1.Visible = false;
            }
            else
            {
                vScrollBar1.Visible = true;
            }
        }
        
        private void SetScrollBarValues()
        {
            vScrollBar1.Minimum = 0;
            hScrollBar1.Minimum = 0;

            if (levelSize.Width * tileSize.Width - splitContainer1.Panel1.Width > 0)
            {
                hScrollBar1.Maximum = levelSize.Width * tileSize.Width;
            }

            if (vScrollBar1.Visible)
            {
                hScrollBar1.Maximum += vScrollBar1.Width;
            }

            hScrollBar1.LargeChange = 128;
            hScrollBar1.SmallChange = 32;

            hScrollBar1.Maximum += hScrollBar1.LargeChange;

            if (levelSize.Height * tileSize.Height - splitContainer1.Panel1.Height > 0)
            {
                vScrollBar1.Maximum = levelSize.Height * tileSize.Height;
            }

            if (hScrollBar1.Visible)
            {
                vScrollBar1.Maximum += hScrollBar1.Height;
            }

            vScrollBar1.LargeChange = 128;
            vScrollBar1.SmallChange = 32;

            vScrollBar1.Maximum += vScrollBar1.LargeChange;
        }

        public void Render()
        {
            // Clear background to teal
            d3D.Clear(splitContainer1.Panel1, bgColor);

            // Initialize things to get drawn


            // Get ready to draw...
            d3D.DeviceBegin();
            d3D.SpriteBegin();

            /////////////////////
            // Draw the things!
            //Background
            if (backImageID != -1 && checkBoxShowBackground.Checked == true)
            {
                tm.Draw(backImageID, 0, 0, 1.0f, 1.0f, Rectangle.Empty, 0, 0, 0.0f, Color.White);
                d3D.Sprite.Flush();
            }

            //Tiles
            for (int l = 5; l >= 0; l--)
            {
                if (showLayer[l] == true)
                {
                    for (int x = 0; x < levelSize.Width; x++)
                    {
                        for (int y = 0; y < levelSize.Height; y++)
                        {
                            if (CullingCheck(x, y))
                            {
                                Rectangle destRect = Rectangle.Empty;
                                destRect.X = x * tileSize.Width - hScrollBar1.Value;
                                destRect.Y = y * tileSize.Height - vScrollBar1.Value;
                                destRect.Size = tileSize;

                                Rectangle srcRect = Rectangle.Empty;
                                srcRect.X = map[l, x, y].X * tileSize.Width;
                                srcRect.Y = map[l, x, y].Y * tileSize.Height;
                                srcRect.Size = tileSize;

                                if (tileSetID != -1)
                                {
                                    tm.Draw(tileSetID, destRect.X, destRect.Y, 1.0f, 1.0f, srcRect,
                                        0, 0, 0.0f, Color.White);
                                    d3D.Sprite.Flush();
                                }
                            }
                        }
                    }
                }
            }

            // Grid
            if (showGrid)
            {
                for (int x = 0; x < levelSize.Width; x++)
                {
                    for (int y = 0; y < levelSize.Height; y++)
                    {
                        if (CullingCheck(x, y))
                        {
                            Rectangle destRect = Rectangle.Empty;
                            destRect.X = x * tileSize.Width - hScrollBar1.Value;
                            destRect.Y = y * tileSize.Height - vScrollBar1.Value;
                            destRect.Size = tileSize;

                            d3D.DrawEmptyRect(destRect, gridColor, 1.0f);

                            if (checkBoxBuildRoom.Checked == true)
                            {
                                Rectangle drawnRoomAdjusted = drawnRoom;
                                drawnRoomAdjusted.X -= hScrollBar1.Value;
                                drawnRoomAdjusted.Y -= vScrollBar1.Value;
                                drawnRoomAdjusted.Width -= hScrollBar1.Value;
                                drawnRoomAdjusted.Height -= hScrollBar1.Value;

                                d3D.DrawEmptyRect(drawnRoomAdjusted, selectedColor);
                            }
                        }
                    }
                }

                // Draw origin lines
                d3D.DrawLine(levelSize.Width * tileSize.Width / 2 - hScrollBar1.Value, 0, levelSize.Width * tileSize.Width / 2 - hScrollBar1.Value, splitContainer1.Panel1.Height, gridColor, 3.0f);
                d3D.DrawLine(0, levelSize.Height * tileSize.Height / 2 - vScrollBar1.Value, splitContainer1.Panel1.Width, levelSize.Height * tileSize.Height / 2 - vScrollBar1.Value, gridColor, 3.0f);
            }

            
            // Stop drawing
            d3D.SpriteEnd();
            d3D.DeviceEnd();

            // Show what you drew
            d3D.Present();

            ////////////////////////////////////////////////////////////
            // Do it again for the tool window
            if (tool != null)
            {
                // Change display param to tool window
                d3D.ChangeDisplayParam(tool.splitContainer1.Panel1);

                // Clear background to teal
                d3D.Clear(tool.splitContainer1.Panel1, bgColor);

                // Initialize things to get drawn


                // Get ready to draw...
                d3D.DeviceBegin();
                d3D.SpriteBegin();

                ////////////////////
                // Draw the things!
                
                //Tiles and grid
                tm.Draw(tileSetID, -tool.hScrollBar1.Value, -tool.vScrollBar1.Value, 1.0f, 1.0f, Rectangle.Empty, 0, 0, 0.0f, Color.White);
                d3D.Sprite.Flush();

                for (int x = 0; x < tileSetSize.Width; x++)
                {
                    for (int y = 0; y < tileSetSize.Height; y++)
                    {
                        Rectangle destRect = Rectangle.Empty;
                        destRect.X = x * tileSize.Width - tool.hScrollBar1.Value;
                        destRect.Y = y * tileSize.Height - tool.vScrollBar1.Value;
                        destRect.Size = tileSize;

                        d3D.DrawEmptyRect(destRect, gridColor, 1.0f);
                    }
                }

                // Selected rect
                Rectangle selectedTileBlock = selectedBlock.selectedTiles;
                selectedTileBlock.X -= tool.hScrollBar1.Value;
                selectedTileBlock.Y -= tool.vScrollBar1.Value;
                selectedTileBlock.Width -= tool.hScrollBar1.Value;
                selectedTileBlock.Height -= tool.hScrollBar1.Value;

                d3D.DrawEmptyRect(selectedTileBlock, selectedColor);

                // Stop drawing
                d3D.SpriteEnd();
                d3D.DeviceEnd();

                // Show what you drew
                d3D.Present();

                // Change display param back to main window
                d3D.ChangeDisplayParam(splitContainer1.Panel1);
            }
        }

        private bool CullingCheck(int x, int y)
        {
            if (x * tileSize.Width - hScrollBar1.Value >= -32 && y * tileSize.Height - vScrollBar1.Value >= -32 &&
                x * tileSize.Width - hScrollBar1.Value < splitContainer1.Panel1.Width && 
                y * tileSize.Height - vScrollBar1.Value < splitContainer1.Panel1.Height)
            {
                return true;
            }
            else return false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void buttonTileSelector_Click(object sender, EventArgs e)
        {
            if (tool == null)
            {
                tool = new Tile_Selector();
                tool.FormClosed += new FormClosedEventHandler(tool_FormClosed);
                tool.SelectBlock += new EventHandler(tool_SelectBlock);

                tool.TileSetWidth = tileSetSize.Width;
                tool.TileSetHeight = tileSetSize.Height;
                tool.TileWidth = tileSize.Width;
                tool.TileHeight = tileSize.Height;

                tool.Show(this);

                d3D.InitManagedDirect3D(tool.splitContainer1.Panel1);
                d3D.InitManagedDirect3D(splitContainer1.Panel1);
                tm.InitManagedTextureManager(d3D.Device, d3D.Sprite);

                tm.LoadTexture(tileSetImagePath, 0);

                if( backImagePath != string.Empty )
                    tm.LoadTexture(backImagePath, 0);
            }

        }

        void tool_SelectBlock(object sender, EventArgs e)
        {
            Tile_Selector tool2 = (Tile_Selector)sender;

            selectedBlock.selectedTiles = tool2.SelectedBlock;

            int lef = selectedBlock.selectedTiles.Left;
            int top = selectedBlock.selectedTiles.Top;
            int wid = selectedBlock.selectedTiles.Width;
            int hit = selectedBlock.selectedTiles.Height;

            selectedBlock.tiles = new Point[wid/tileSize.Width, hit/tileSize.Height];

            for (int x = 0; x < wid / tileSize.Width; x++)
            {
                for (int y = 0; y < hit / tileSize.Height; y++)
                {
                    selectedBlock.tiles[x, y] = new Point(lef / tileSize.Width + x, 
                        top / tileSize.Height + y);
                }
            }
            
        }

        void tool_FormClosed(object sender, FormClosedEventArgs e)
        {
            tool = null;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            looping = false;
        }

        private void buttonLoadBackground_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofile = new OpenFileDialog();
            ofile.Title = "Load Background Image...";

            string path = Environment.CurrentDirectory;

            if (path.Contains("\\bin\\Debug"))
            {
                path = "..\\..\\Resources\\";
            }

            ofile.InitialDirectory = path;
            ofile.RestoreDirectory = true;

            if (ofile.CheckPathExists == false)
            {
                ofile.InitialDirectory = Environment.CurrentDirectory;
            }
            else
            {
                DialogResult dlgRes = ofile.ShowDialog(this);
                if (dlgRes == DialogResult.OK)
                {
                    backImagePath = ofile.FileName;
                    backFileName = ofile.SafeFileName;
                    backImageID = tm.LoadTexture(ofile.FileName, 0);
                }
                else if (dlgRes == DialogResult.Cancel)
                {

                }
            }
        }

        private void buttonGridColor_Click(object sender, EventArgs e)
        {
            ColorDialog dlg = new ColorDialog();

            dlg.Color = buttonGridColor.BackColor;

            if (DialogResult.OK == dlg.ShowDialog())
            {
                buttonGridColor.BackColor = dlg.Color;
                gridColor = dlg.Color;
            }
        }

        private void buttonSelectionColor_Click(object sender, EventArgs e)
        {
            ColorDialog dlg = new ColorDialog();

            dlg.Color = buttonSelectionColor.BackColor;

            if (DialogResult.OK == dlg.ShowDialog())
            {
                buttonSelectionColor.BackColor = dlg.Color;
                selectedColor = dlg.Color;
            }
        }

        private void splitContainer1_Panel1_MouseMove(object sender, MouseEventArgs e)
        {
            toolStripStatusLabelPixelCoord.Text = "Pixel Coord: " + ((e.X + hScrollBar1.Value) + levelSize.Width * tileSize.Width / 2 - levelSize.Width * tileSize.Width)
                + ", " + ((e.Y + vScrollBar1.Value) + levelSize.Height * tileSize.Height / 2 - levelSize.Height * tileSize.Height);

            toolStripStatusLabelTileCoord.Text = "Tile Coord: " + ((e.X + hScrollBar1.Value) / tileSize.Width) + ", " + ((e.Y + vScrollBar1.Value) / tileSize.Height);

            if (checkBoxBuildRoom.Checked == false)
            {
                if (e.Button == MouseButtons.Left || e.Button == MouseButtons.Right)
                    splitContainer1_Panel1_MouseClick(this, e);
            }
            else if (checkBoxBuildRoom.Checked == true && e.Button == MouseButtons.Left)
            {
                roomEnd = new Point(e.X + hScrollBar1.Value, e.Y + vScrollBar1.Value);

                int wid = roomEnd.X / tileSize.Width - roomStart.X / tileSize.Width;
                int hit = roomEnd.Y / tileSize.Height - roomStart.Y / tileSize.Height;

                if (wid >= 0 && hit >= 0)
                {
                    drawnRoom = new Rectangle(roomStart.X / tileSize.Width * tileSize.Width, roomStart.Y / tileSize.Height * tileSize.Height,
                        (wid + 1) * tileSize.Width, (hit + 1) * tileSize.Height);

                    int tempLeft = drawnRoom.Left / tileSize.Width;
                    int tempTop = drawnRoom.Top / tileSize.Height;
                    int tempRight = drawnRoom.Right / tileSize.Width - 1;
                    int tempBottom = drawnRoom.Bottom / tileSize.Height - 1;

                    textBoxLeft.Text   = tempLeft.ToString();
                    textBoxTop.Text    = tempTop.ToString();
                    textBoxRight.Text  = tempRight.ToString();
                    textBoxBottom.Text = tempBottom.ToString();
                }
            }
        }

        private void numericUpDownLevelWidth_ValueChanged(object sender, EventArgs e)
        {
            int oldLevelWidth = levelSize.Width;
            levelSize.Width = (int)(numericUpDownLevelWidth.Value);

            toolStripStatusLabelResizeMap.Visible = true;
            resizeLevel.Visible = true;
            resizeLevel.Minimum = 1;
            resizeLevel.Maximum = 6 * levelSize.Width * levelSize.Height;
            resizeLevel.Value = 1;
            resizeLevel.Step = 1;

            Point[, ,] tempMap = new Point[6, oldLevelWidth, levelSize.Height];
            tempMap = map;

            String[, ,] tempEvents = new String[6, oldLevelWidth, levelSize.Height];
            tempEvents = events;

            map = new Point[6, levelSize.Width, levelSize.Height];
            events = new String[6, levelSize.Width, levelSize.Height];

            for (int l = 0; l < 6; l++)
            {
                for (int x = 0; x < levelSize.Width; x++)
                {
                    for (int y = 0; y < levelSize.Height; y++)
                    {
                        map[l, x, y] = new Point(7, 0);

                        events[l, x, y] = "0";

                        if (x < oldLevelWidth)
                        {
                            map[l, x, y] = tempMap[l, x, y];
                            events[l, x, y] = tempEvents[l, x, y];
                        }
                        resizeLevel.PerformStep();
                    }
                }
            }
            resizeLevel.Visible = false;
            toolStripStatusLabelResizeMap.Visible = false;
        }

        private void numericUpDownLevelHeight_ValueChanged(object sender, EventArgs e)
        {
            int oldLevelHeight = levelSize.Height;

            levelSize.Height = (int)numericUpDownLevelHeight.Value;

            toolStripStatusLabelResizeMap.Visible = true;
            resizeLevel.Visible = true;
            resizeLevel.Minimum = 1;
            resizeLevel.Maximum = 6 * levelSize.Width * levelSize.Height;
            resizeLevel.Value = 1;
            resizeLevel.Step = 1;

            Point[, ,] tempMap = new Point[6, levelSize.Width, oldLevelHeight];
            tempMap = map;

            String[, ,] tempEvents = new String[6, oldLevelHeight, levelSize.Height];
            tempEvents = events;

            map = new Point[6, levelSize.Width, levelSize.Height];
            events = new String[6, levelSize.Width, levelSize.Height];

            for (int l = 0; l < 6; l++)
            {
                for (int x = 0; x < levelSize.Width; x++)
                {
                    for (int y = 0; y < levelSize.Height; y++)
                    {
                        map[l, x, y] = new Point(7, 0);

                        events[l, x, y] = "0";

                        if (y < oldLevelHeight)
                        {
                            map[l, x, y] = tempMap[l, x, y];
                            events[l, x, y] = tempEvents[l, x, y];
                        }
                        resizeLevel.PerformStep();
                    }
                }
            }
            resizeLevel.Visible = false;
            toolStripStatusLabelResizeMap.Visible = false;
        }

        private void numericUpDownTileWidth_ValueChanged(object sender, EventArgs e)
        {
            tileSize.Width = (int)numericUpDownTileWidth.Value;
        }

        private void numericUpDownTileHeight_ValueChanged(object sender, EventArgs e)
        {
            tileSize.Height = (int)numericUpDownTileHeight.Value;
        }

        private void checkBoxShowGrid_CheckedChanged(object sender, EventArgs e)
        {
            showGrid = checkBoxShowGrid.Checked;
        }

        private void checkBoxLayersShowAll_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxLayersShowAll.Checked == true)
            {
                for (int x = 0; x < 6; x++)
                {
                    checkedListBoxShowLayers.SetItemChecked(x, true);
                    showLayer[x] = true;
                }
            }
        }

        private void splitContainer1_Panel1_MouseClick(object sender, MouseEventArgs e)
        {
            Point mouse = new Point(e.X + hScrollBar1.Value, e.Y + vScrollBar1.Value);

            if (mouse.X >= 0 && mouse.Y >= 0 && mouse.X < tileSize.Width * levelSize.Width && mouse.Y < tileSize.Height * levelSize.Height)
            {
                if (e.Button == MouseButtons.Left)
                {
                    for (int x = 0; x < selectedBlock.selectedTiles.Width/tileSize.Width; x++)
                    {
                        for (int y = 0; y < selectedBlock.selectedTiles.Height/tileSize.Height; y++)
                        {
                            if ((mouse.X / tileSize.Width) + x >= 0 && (mouse.Y / tileSize.Height) + y >= 0 &&
                                (mouse.X / tileSize.Width) + x < levelSize.Width && (mouse.Y / tileSize.Height) + y < levelSize.Height)
                                map[drawLayer, (mouse.X / tileSize.Width) + x, (mouse.Y / tileSize.Height) + y] = selectedBlock.tiles[x, y];
                        }
                    }
                }

                if (e.Button == MouseButtons.Right)
                    map[drawLayer, mouse.X / tileSize.Width, mouse.Y / tileSize.Height] = new Point(7, 0);
            }
        }

        private void radioButtonDrawLayerForeground_CheckedChanged(object sender, EventArgs e)
        {
            if( radioButtonDrawLayerForeground.Checked == true )
                drawLayer = 0;
        }

        private void radioButtonDrawLayerExternal_CheckedChanged(object sender, EventArgs e)
        {
            if( radioButtonDrawLayerExternal.Checked == true )
                drawLayer = 1;
        }

        private void radioButtonDrawLayerCollidable_CheckedChanged(object sender, EventArgs e)
        {
            if( radioButtonDrawLayerCollidable.Checked == true )
                drawLayer = 2;
        }

        private void radioButtonDrawLayerFloor_CheckedChanged(object sender, EventArgs e)
        {
            if( radioButtonDrawLayerFloor.Checked == true )
                drawLayer = 3;
        }

        private void radioButtonDrawLayerUnderFloor_CheckedChanged(object sender, EventArgs e)
        {
            if( radioButtonDrawLayerUnderFloor.Checked == true )
                drawLayer = 4;
        }

        private void radioButtonDrawLayerData_CheckedChanged(object sender, EventArgs e)
        {
            if( radioButtonDrawLayerData.Checked == true )
                drawLayer = 5;
        }

        private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
        {
            vScrollBar1.Left = e.SplitX - 20;
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            looping = false;
            Application.Restart();
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Filter = "All Files|*.*|Xml Files|*.xml";
            dlg.FilterIndex = 2;
            dlg.DefaultExt = "xml";

            if (DialogResult.OK == dlg.ShowDialog())
            {
                // Level
                XElement xRoot = new XElement("Level");

                // Map
                XElement xMap = new XElement("Map");
                xRoot.Add(xMap);

                XAttribute xTileFilePath = new XAttribute("FilePath", tileSetFileName);
                xMap.Add(xTileFilePath);

                XAttribute xTileWidth = new XAttribute("TileWidth", tileSize.Width);
                xMap.Add(xTileWidth);

                XAttribute xTileHeight = new XAttribute("TileHeight", tileSize.Height);
                xMap.Add(xTileHeight);

                XAttribute xTileSetWidth = new XAttribute("TileSetWidth", tileSetSize.Width);
                xMap.Add(xTileSetWidth);

                XAttribute xTileSetHeight = new XAttribute("TileSetHeight", tileSetSize.Height);
                xMap.Add(xTileSetHeight);

                XAttribute xMapWidth = new XAttribute("MapWidth", levelSize.Width);
                xMap.Add(xMapWidth);

                XAttribute xMapHeight = new XAttribute("MapHeight", levelSize.Height);
                xMap.Add(xMapHeight);

                // Layers
                for (int l = 0; l < 6; l++)
                {
                    XElement xLayer = new XElement("Layer");
                    xMap.Add(xLayer);

                    XAttribute xTileLayer = new XAttribute("TileLayer", l);
                    xLayer.Add(xTileLayer);

                    XAttribute xScrollRate = new XAttribute("ScrollRate", layerScrollRates[l]);
                    xLayer.Add(xScrollRate);

                    // Tiles
                    for (int x = 0; x < levelSize.Width; x++)
                    {
                        for (int y = 0; y < levelSize.Height; y++)
                        {
                            XElement xTile = new XElement("Tile");
                            xLayer.Add(xTile);

                            int tileID = (((map[l, x, y].X)) + ((map[l, x, y].Y)) * tileSetSize.Width);

                            XAttribute xTileID = new XAttribute("TileID", tileID);
                            xTile.Add(xTileID);

                            XAttribute xEventID = new XAttribute("EventID", events[l, x, y].ToString());
                            xTile.Add(xEventID);
                        }
                    }
                }

                // Rooms
                XElement xRooms = new XElement("Rooms");
                xMap.Add(xRooms);

                XAttribute xNumRooms = new XAttribute("NumberOfRooms", rooms.Count());
                xRooms.Add(xNumRooms);

                if (rooms != null)
                {
                    foreach (Rectangle roomRect in rooms)
                    {
                        XElement xRoom = new XElement("Room");
                        xRooms.Add(xRoom);

                        XAttribute xLeft = new XAttribute("Left", roomRect.Left);
                        xRoom.Add(xLeft);

                        XAttribute xTop = new XAttribute("Top", roomRect.Top);
                        xRoom.Add(xTop);

                        XAttribute xRight = new XAttribute("Right", roomRect.Right);
                        xRoom.Add(xRight);

                        XAttribute xBottom = new XAttribute("Bottom", roomRect.Bottom);
                        xRoom.Add(xBottom);
                    }
                }

                // Background
                XElement xBackground = new XElement("Background");
                xRoot.Add(xBackground);

                XAttribute xBGFilePath = new XAttribute("FilePath", backFileName);
                xBackground.Add(xBGFilePath);

                // Objects
                XElement xObjects = new XElement("Objects");
                xRoot.Add(xObjects);

                // Enemies
                XElement xEnemies = new XElement("Enemies");
                xObjects.Add(xEnemies);

                // Enemy
                // foreach (enemy in listofenemies)
                // XElement xEnemy = new XElement("Enemy");

                // Chests
                XElement xChests = new XElement("Chests");
                xObjects.Add(xChests);

                // Chest
                //foreach (chest in listofchests)
                // XElement xChest = new XElement("Chest");

                // Doors
                XElement xDoors = new XElement("Doors");
                xObjects.Add(xDoors);

                // Door
                // foreach (door in listofdoors)
                // XElement xDoor = new XElement("Door");

                // Terminals
                XElement xTerminals = new XElement("Terminals");
                xObjects.Add(xTerminals);

                // Terminal
                // foreach (terminal in listofterminals)
                // XElement xTerminal = new XElement("Terminal");

                // Nodes
                XElement xNodes = new XElement("Nodes");
                xObjects.Add(xNodes);

                // Node
                // foreach (node in listofnodes)
                // XElement xNode = new XElement("Node");

                xRoot.Save(dlg.FileName);
            }
        }

        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
            saveToolStripMenuItem_Click(this, EventArgs.Empty);
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "All Files|*.*|Xml Files|*.xml";
            dlg.FilterIndex = 2;

            if (DialogResult.OK == dlg.ShowDialog())
            {
                XElement xRoot = XElement.Load(dlg.FileName);

                // Level
                IEnumerable<XElement> xLevel = xRoot.Elements();

                // Map
                XElement xMap = xLevel.First();

                // Layers
                IEnumerable<XElement> xLayer = xMap.Elements("Layer");
                

                XAttribute xTileFile = xMap.Attribute("FilePath");
                XAttribute xTileWidth = xMap.Attribute("TileWidth");
                XAttribute xTileHeight = xMap.Attribute("TileHeight");
                XAttribute xTileSetWidth = xMap.Attribute("TileSetWidth");
                XAttribute xTileSetHeight = xMap.Attribute("TileSetHeight");
                XAttribute xMapWidth = xMap.Attribute("MapWidth");
                XAttribute xMapHeight = xMap.Attribute("MapHeight");

                string tileFileName = xTileFile.Value.ToString();
                string path = Environment.CurrentDirectory;

                if (path.Contains("\\bin\\Debug"))
                {
                    path = "..\\..\\Resources\\";
                    path += tileFileName;
                }
                else
                {
                    path += "Resources\\";
                    path += tileFileName;
                }

                tileSetImagePath = path;
                tileSetFileName = tileFileName;

                tileSetID = tm.LoadTexture(path, 0);

                int xTW = int.Parse(xTileWidth.Value);
                int xTH = int.Parse(xTileHeight.Value);

                tileSize.Width = xTW;
                tileSize.Height = xTH;

                int xTSW = int.Parse(xTileSetWidth.Value);
                int xTSH = int.Parse(xTileSetHeight.Value);

                tileSetSize.Width = xTSW;
                tileSetSize.Height = xTSH;

                int xW = int.Parse(xMapWidth.Value);
                int xH = int.Parse(xMapHeight.Value);

                map = new Point[6, xW, xH];
                levelSize.Width = xW;
                levelSize.Height = xH;

                // Layer
                foreach( XElement layer in xLayer)
                {
                    XAttribute tileLayer = layer.Attribute("TileLayer");
                    XAttribute scrollRate = layer.Attribute("ScrollRate");

                    int xTileLayer = int.Parse(tileLayer.Value);
                    int xScrollRate = int.Parse(scrollRate.Value);

                    layerScrollRates[xTileLayer] = xScrollRate;

                    // Tiles
                    IEnumerable<XElement> xTiles = layer.Elements("Tile");

                    int x = 0;
                    int y = 0;

                    foreach (XElement tile in xTiles)
                    {
                        // Tile
                        XAttribute xTileID = tile.Attribute("TileID");
                        XAttribute xEventID = tile.Attribute("EventID");

                        int tileID = int.Parse(xTileID.Value);

                        map[xTileLayer, y, x] = new Point(tileID % tileSetSize.Width, tileID / tileSetSize.Width);

                        x++;

                        if (x == levelSize.Width)
                        {
                            y++;
                            x = 0;
                        }
                    }
                }

                // Rooms
                XElement xRooms = xMap.Element("Rooms");
                XAttribute xNumRooms = xRooms.Attribute("NumberOfRooms");

                int numRooms = int.Parse(xNumRooms.Value);

                rooms = new Rectangle[numRooms];

                IEnumerable<XElement> xRoomList = xRooms.Elements("Room");

                int rectIndex = 0;

                foreach (XElement room in xRoomList)
                {
                    //Room
                    XElement xRoom = room.Element("Room");
                    XAttribute xLeft = xRoom.Attribute("Left");
                    XAttribute xTop = xRoom.Attribute("Top");
                    XAttribute xRight = xRoom.Attribute("Right");
                    XAttribute xBottom = xRoom.Attribute("Bottom");

                    int left = int.Parse(xLeft.Value);
                    int top = int.Parse(xTop.Value);
                    int right = int.Parse(xRight.Value);
                    int bottom = int.Parse(xBottom.Value);

                    rooms[rectIndex] = new Rectangle(left, top, right - left, bottom - top);

                    rectIndex++;
                }

                // Background
                XElement xBackground = xRoot.Element("Background");
                XAttribute xBGFilePath = xBackground.Attribute("FilePath");

                string bgFilePath = xBGFilePath.Value.ToString();
                string bgPath = Environment.CurrentDirectory;

                if (bgPath.Contains("\\bin\\Debug"))
                {
                    bgPath = "..\\..\\Resources\\";
                    bgPath += bgFilePath;
                }
                else
                {
                    bgPath += "Resources\\";
                    bgPath += bgFilePath;
                }

                backImagePath = bgPath;
                backFileName = bgFilePath;

                backImageID = tm.LoadTexture(bgPath, 0);

                // Objects
                XElement xObjects = xRoot.Element("Objects");
                
                // Enemies
                XElement xEnemies = xObjects.Element("Enemies");

                IEnumerable<XElement> xEnemyList = xEnemies.Elements("Enemy");

                foreach (XElement enemy in xEnemyList)
                {
                    // Enemy
                    XAttribute xType = enemy.Attribute("Type");
                    XAttribute xPosX = enemy.Attribute("PosX");
                    XAttribute xPosY = enemy.Attribute("PosY");


                }

                // Chests
                // Chest

                // Doors
                // Door

                // Terminals
                // Terminal
                
                // Nodes
                // Node
            }
        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            openToolStripMenuItem_Click(this, EventArgs.Empty);
        }

        private void numericUpDownScrollRate0_ValueChanged(object sender, EventArgs e)
        {
            layerScrollRates[0] = (int)numericUpDownScrollRate0.Value;
        }

        private void numericUpDownScrollRate1_ValueChanged(object sender, EventArgs e)
        {
            layerScrollRates[1] = (int)numericUpDownScrollRate1.Value;
        }

        private void numericUpDownScrollRate2_ValueChanged(object sender, EventArgs e)
        {
            layerScrollRates[2] = (int)numericUpDownScrollRate2.Value;
        }

        private void numericUpDownScrollRate3_ValueChanged(object sender, EventArgs e)
        {
            layerScrollRates[3] = (int)numericUpDownScrollRate3.Value;
        }

        private void numericUpDownScrollRate4_ValueChanged(object sender, EventArgs e)
        {
            layerScrollRates[4] = (int)numericUpDownScrollRate4.Value;
        }

        private void numericUpDownScrollRate5_ValueChanged(object sender, EventArgs e)
        {
            layerScrollRates[5] = (int)numericUpDownScrollRate5.Value;
        }

        private void buttonAddRoom_Click(object sender, EventArgs e)
        {
            if (numberOfRooms > 0)
            {
                numberOfRooms++;
                Rectangle[] tempRooms = new Rectangle[numberOfRooms - 1];
                tempRooms = rooms;

                rooms = new Rectangle[numberOfRooms];

                for (int x = 0; x < numberOfRooms - 1; x++)
                {
                    rooms[x] = tempRooms[x];
                }
            }
            else if (numberOfRooms == 0)
            {
                numberOfRooms++;
                rooms = new Rectangle[numberOfRooms];
            }

            rooms[numberOfRooms - 1] = drawnRoom;

            roomStart = Point.Empty;
            roomEnd = Point.Empty;
            drawnRoom = Rectangle.Empty;

        }

        private void checkBoxBuildRoom_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBoxBuildRoom.Checked == true)
            {
                selectedBlock.tiles = null;
                selectedBlock.selectedTiles = Rectangle.Empty;
            }
        }

        private void buttonBGColor_Click(object sender, EventArgs e)
        {
            ColorDialog dlg = new ColorDialog();

            dlg.Color = buttonBGColor.BackColor;

            if (DialogResult.OK == dlg.ShowDialog())
            {
                buttonBGColor.BackColor = dlg.Color;
                bgColor = dlg.Color;
            }
        }

        private void splitContainer1_Panel1_MouseDown(object sender, MouseEventArgs e)
        {
            if( checkBoxBuildRoom.Checked == true )
                roomStart = new Point(e.X + hScrollBar1.Value, e.Y + vScrollBar1.Value);
        }

        private void splitContainer1_Panel1_MouseUp(object sender, MouseEventArgs e)
        {
            if (checkBoxBuildRoom.Checked == true)
            {
                roomEnd = new Point(e.X + hScrollBar1.Value, e.Y + vScrollBar1.Value);

                int wid = roomEnd.X / tileSize.Width - roomStart.X / tileSize.Width;
                int hit = roomEnd.Y / tileSize.Height - roomStart.Y / tileSize.Height;

                if (wid >= 0 && hit >= 0)
                {
                    drawnRoom = new Rectangle(roomStart.X / tileSize.Width * tileSize.Width, roomStart.Y / tileSize.Height * tileSize.Height,
                        (wid + 1) * tileSize.Width, (hit + 1) * tileSize.Height);
                }
            }

        }
    }
}